#pragma once
#include <memory>
#include <unordered_map>
#include "Epoll.hpp"
#include "Connect.hpp"


namespace ReactorModule
{
    using namespace EpollModule;
    using namespace ConnectModule;

    using connection_t = std::shared_ptr<Connect>;

    const static int maxevents = 64;

    class Reactor
    {   
    public:
        Reactor():_epoller(std::make_unique<Epoll>()), _isrunning(false)
        {}
        void Init()
        {
            _epoller->Init();
        }
        void Loop()
        {
            _isrunning = true;
            int timeout = -1;
            while(_isrunning)
            {
                int ready_num = _epoller->Wait(_revents,maxevents,timeout);
                // 这里只要返回，就是成功了，就要对这些返回的事件进行处理(轮转)(基于事件驱动的派发器)
                Dispatcher(ready_num);
            } 
            _isrunning = false;
        }
        bool BuiltConnection(connection_t connect)
        {
            if(HasConnection(connect->Fd()))
                return false;
            _fdconnection[connect->Fd()] = connect;
            _epoller->AddCtl(connect->Fd(),EPOLLIN | EPOLLET);
            connect->SetOwner(this);
            LOG(LogLevel::DEBUG) << "Built A New Connection, fd is " << connect->Fd();
            return true;
        } 
        bool RemoveConnection(int fd)
        {
            if(!HasConnection(fd))
                return false;
            _epoller->DelCtl(fd);
            _fdconnection.erase(fd);
            return true;
        }
        void Stop()
        {
            _isrunning = false;
        }
        void EnableReadWrite(int sockfd, bool readable, bool writeable)
        {
            if (HasConnection(sockfd))
            {
                // 修改用户层connection的事件
                uint32_t events = ((readable ? EPOLLIN : 0) | (writeable ? EPOLLOUT : 0) | EPOLLET);
                _fdconnection[sockfd]->SetEvents(events);
                // 写透到内核中
                _epoller->ModCtl(sockfd, _fdconnection[sockfd]->Events());
            }
        }
        ~Reactor()
        {}
    private:
        void Dispatcher(int ready_num)
        {
            for(int i = 0; i < ready_num; i++)
            {
                int fd = _revents[i].data.fd;
                uint32_t revent = _revents[i].events;

                // 将错误全部转成IO事件，最后让IO事件做异常处理
                if((revent & EPOLLERR)||(revent & EPOLLHUP))
                    revent = (EPOLLIN | EPOLLOUT);
                // 对读事件进行处理，这里需要确保它
                if((revent & EPOLLIN) && HasConnection(fd))
                    _fdconnection[fd]->Recv();
                // 对事件进行处理
                if((revent & EPOLLOUT) && HasConnection(fd))
                    _fdconnection[fd]->Send();
            }
        }
        // 查看是否存在该连接
        bool HasConnection(int fd)
        {   
            return _fdconnection.find(fd) != _fdconnection.end();
        }
    private:
        std::unique_ptr<Epoll> _epoller; // epoller模型
        std::unordered_map<int,connection_t> _fdconnection; //epoller获取到的文件描述符和连接的映射关系，核心关心，负责上下层沟通的桥梁
        struct epoll_event _revents[maxevents];   // 事件的返回结果
        bool _isrunning;
    };
}